use std::collections::HashMap;

use futures::StreamExt;
use libp2p::{PeerId, core::transport::ListenerId, swarm::Swarm};
use tokio::sync::{mpsc, oneshot};
use tracing::info;

use crate::network_api::{P2PCommandOfApp, P2PEventForApp};
use crate::network_core::P2pNetWorkError;
use crate::network_core::network_core_impl::combined_behaviour::{
    CombinedBehaviour, KadEventMetaData, RequestResponseEventMetaData,
};
use crate::network_core::network_core_inner_api::CommandOfNetWorkCore;

mod command_handler;
mod event_handler_and_dispatcher;

// Block chain p2p manager
pub(crate) struct NetworkManager {
    swarm: Swarm<CombinedBehaviour>,
    command_receiver_for_network_core: mpsc::Receiver<CommandOfNetWorkCore>,
    command_receiver_for_app: mpsc::Receiver<P2PCommandOfApp>,

    pending_dial: HashMap<PeerId, oneshot::Sender<Result<(), P2pNetWorkError>>>,

    local_listeners: Vec<ListenerId>,
    local_peer_id: PeerId,

    kad_metadata: KadEventMetaData,
    request_response_metadata: RequestResponseEventMetaData,
    event_sender_for_app: mpsc::Sender<P2PEventForApp>,
}

impl NetworkManager {
    pub(crate) fn new(
        swarm: Swarm<CombinedBehaviour>,
        command_receiver_for_network_core: mpsc::Receiver<CommandOfNetWorkCore>,
        command_receiver_for_app: mpsc::Receiver<P2PCommandOfApp>,
        event_sender_for_app: mpsc::Sender<P2PEventForApp>,
    ) -> Self {
        let local_peer_id = *swarm.local_peer_id();

        Self {
            swarm,
            command_receiver_for_network_core,
            command_receiver_for_app,
            pending_dial: Default::default(),

            local_listeners: Default::default(),
            local_peer_id,

            kad_metadata: KadEventMetaData::new(),
            request_response_metadata: RequestResponseEventMetaData::new(
                event_sender_for_app.clone(),
            ),
            event_sender_for_app,
        }
    }

    pub(crate) async fn network_core_main_loop(
        mut self,
        mut shutdown_signal: tokio::sync::watch::Receiver<bool>,
        // mut event_receiver_for_network_core: mpsc::Receiver<NetWorkCoreEvent>,
    ) {
        println!("🚀 Starting the network-core event loop task ...");
        bc_util::print_task_and_thread_id("P2P network main loop task");
        loop {
            // info!("Waiting for next network event.");
            tokio::select! {
                event = self.swarm.select_next_some() => self.handle_and_dispatch_event(event).await,

                command = self.command_receiver_for_network_core.recv() => match command {
                    Some(c) => self.handle_command(c).await,
                    None=>  {
                        // Command channel closed, thus shutting down the network event loop.
                        info!("Command channel for network core shutting down.");
                        break
                    },
                },
                command_from_app = self.command_receiver_for_app.recv() => match command_from_app {
                    Some(c) => self.handle_command_of_app(c).await,
                    None=>  {
                        // Command channel closed, thus shutting down the network event loop.
                        info!("Command channel for APP shutting down.");
                        break
                    },
                },
                _ = shutdown_signal.changed() => {
                    // 如果 shutdown_signal 发生变化，再次检查其值
                    if *shutdown_signal.borrow() {
                        info!("Shutdown signal received for network event loop task.");
                        break;
                    }
                },
            }
        }
        // self.cleanup_swarm().await.expect("Cleanup swarm.");

        println!("🛑 The network-core event loop task stopped.");
    }
}
